home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac-Source 1994 July
/
Mac-Source_July_1994.iso
/
Other Langs
/
MacPerl ƒ
/
Perl Source ƒ
/
MacPerl
/
MPConsole.cp
< prev
next >
Wrap
Text File
|
1994-01-19
|
9KB
|
443 lines
/*********************************************************************
Project : MacPerl - Standalone Perl
File : MPConsole.cp - Console interface for GUSI
Author : Matthias Neeracher
Started : 31May93 Language : MPW C/C++
Modified : 14Aug93 MN Remember rectangles
30Aug93 MN ShowWindow -> DoShowWindow
Last : 30Aug93
*********************************************************************/
#include "GUSI_P.h"
#include <Resources.h>
#include <Windows.h>
#include <Errors.h>
#include <Folders.h>
#include <PLStringFuncs.h>
#include <SysEqu.h>
#include <OSEvents.h>
#include <ioctl.h>
#include <sys/types.h>
#include <Signal.h>
extern "C" {
#include "MPConsole.h"
#include "MPGlobals.h"
#include "MPAppleEvents.h"
#include "MPWindow.h"
#include "MPFile.h"
#include "MPMain.h"
}
#define AF_CONSOLE 17
class MPConsoleSocket; // That's what this file's all about
class MPConsoleSocket : public Socket {
friend class MPConsoleSocketDomain;
friend void CloseConsole(Ptr cookie);
friend void HarvestConsole(DPtr doc, MPConsoleSocket * sock);
friend int GUSIConsoleSpin(spin_msg msg, long arg);
MPConsoleSocket(DPtr window);
virtual ~MPConsoleSocket();
DPtr window;
Handle input;
Boolean nonblocking;
Boolean eof;
public:
virtual int read(void * buffer, int buflen);
virtual int write(void * buffer, int buflen);
virtual int fcntl(unsigned int cmd, int arg);
virtual void pre_select(Boolean wantRead, Boolean wantWrite, Boolean wantExcept);
virtual int select(Boolean * canRead, Boolean * canWrite, Boolean * exception);
virtual void post_select(Boolean wantRead, Boolean wantWrite, Boolean wantExcept);
virtual int ioctl(unsigned int request, void *argp);
virtual int isatty();
};
class MPConsoleSocketDomain : public DeviceSocketDomain {
MPConsoleSocket * first;
public:
MPConsoleSocketDomain() : DeviceSocketDomain(AF_CONSOLE) { }
virtual Socket * open(const char * filename, int oflag);
};
MPConsoleSocketDomain MPConsoleSockets;
#pragma segment MPConsole
/************************ MPConsoleSocket members ************************/
void HarvestConsole(DPtr doc, MPConsoleSocket * sock)
{
HLock((*doc->theText)->hText);
char * chr = *(*doc->theText)->hText + (*doc->theText)->teLength;
char * end = *(*doc->theText)->hText + doc->u.cons.fence;
if (gGotEof == doc) {
PtrAndHand(end, sock->input, chr - end);
doc->u.cons.fence = (*doc->theText)->teLength;
sock->eof = true;
} else
while (chr-- > end)
if (*chr == '\n') {
PtrAndHand(end, sock->input, ++chr - end);
doc->u.cons.fence = chr - *(*doc->theText)->hText;
break;
}
HUnlock((*doc->theText)->hText);
}
MPConsoleSocket::MPConsoleSocket(DPtr window)
: window(window)
{
nonblocking = false;
eof = false;
input = NewHandle(0);
window->u.cons.cookie = Ptr(this);
}
void CloseConsole(Ptr cookie)
{
if (cookie)
((MPConsoleSocket *) cookie)->window = nil;
}
MPConsoleSocket::~MPConsoleSocket()
{
DisposeHandle(input);
if (window)
window->u.cons.cookie = nil;
}
int MPConsoleSocket::fcntl(unsigned int cmd, int arg)
{
switch (cmd) {
case F_GETFL:
if (nonblocking)
return FNDELAY;
else
return 0;
case F_SETFL:
if (arg & FNDELAY)
nonblocking = true;
else
nonblocking = false;
return 0;
default:
return GUSI_error(EOPNOTSUPP);
}
}
int MPConsoleSocket::ioctl(unsigned int request, void *argp)
{
switch (request) {
case FIONBIO:
nonblocking = (Boolean) *(long *) argp;
return 0;
case FIONREAD:
*(unsigned long *) argp = GetHandleSize(input);
return 0;
case FIOINTERACTIVE:
return 0;
case WIOSELECT:
if (window)
SelectWindow(window->theWindow);
return 0;
default:
return GUSI_error(EOPNOTSUPP);
}
}
int MPConsoleSocket::read(void * buffer, int buflen)
{
int avail;
avail = int(GetHandleSize(input));
if (!avail) {
if (eof) {
eof = false;
return 0;
}
if (!window)
return 0;
else if (nonblocking)
return GUSI_error(EWOULDBLOCK);
else {
if (!((WindowPeek) window->theWindow)->visible)
DoShowWindow(window->theWindow);
if (!((WindowPeek) window->theWindow)->hilited)
SelectWindow(window->theWindow);
window->u.cons.selected = true;
ShowWindowStatus();
SPIN(!(avail = int(GetHandleSize(input))) && !eof && window, SP_STREAM_READ, 0);
if (!avail && eof)
eof = false;
window->u.cons.selected = false;
ShowWindowStatus();
}
}
buflen = min(avail, buflen);
HLock(input);
memcpy(buffer, *input, buflen);
if (avail -= buflen)
memcpy(*input, *input+buflen, avail);
HUnlock(input);
SetHandleSize(input, avail);
return buflen;
}
int MPConsoleSocket::write(void * buffer, int buflen)
{
short oldStart;
short oldEnd;
int len = buflen;
if (!window)
return GUSI_error(ESHUTDOWN);
HarvestConsole(window, this);
if (len > window->u.cons.memory) {
buffer = (void *) (Ptr(buffer) + len - window->u.cons.memory);
len = window->u.cons.memory;
}
(*window->theText)->teLength += buflen;
EnforceMemory(window, window->theText);
(*window->theText)->teLength -= buflen;
oldStart = (*window->theText)->selStart;
oldEnd = (*window->theText)->selEnd;
if (oldStart >= window->u.cons.fence)
oldStart += buflen;
if (oldEnd >= window->u.cons.fence)
oldEnd += buflen;
TESetSelect(window->u.cons.fence, window->u.cons.fence, window->theText);
TEInsert(buffer, buflen, window->theText);
if (!((WindowPeek) window->theWindow)->visible) {
HideControl(window->vScrollBar);
HideControl(window->hScrollBar);
DoShowWindow(window->theWindow);
}
ShowSelect(window);
DrawPageExtras(window);
TESetSelect(oldStart, oldEnd, window->theText);
if (window->u.cons.fence < 32767)
window->u.cons.fence += buflen;
return buflen;
}
static Boolean StatusNeedsUpdate = false;
void MPConsoleSocket::pre_select(Boolean canRead, Boolean, Boolean)
{
if (canRead && window) {
StatusNeedsUpdate = window->u.cons.selected = true;
if (!((WindowPeek) window->theWindow)->visible)
DoShowWindow(window->theWindow);
}
}
void MPConsoleSocket::post_select(Boolean canRead, Boolean, Boolean)
{
if (canRead && window)
StatusNeedsUpdate = window->u.cons.selected = false;
}
int MPConsoleSocket::select(Boolean * canRead, Boolean * canWrite, Boolean * exception)
{
int goodies = 0;
if (StatusNeedsUpdate) {
ShowWindowStatus();
StatusNeedsUpdate = false;
}
if (canRead)
if (*canRead = (GetHandleSize(input) > 0 || eof))
++goodies;
if (canWrite) {
*canWrite = true;
++goodies;
}
if (exception)
*exception = false;
return goodies;
}
int MPConsoleSocket::isatty()
{
return 1;
}
/********************* MPConsoleSocketDomain member **********************/
#pragma force_active on
static Boolean spinInstalled = false;
Socket * MPConsoleSocketDomain::open(const char * filename, int flags)
{
DPtr doc;
Socket * sock = nil;
char title[256];
Boolean nudoc = false;
strncpy(title, filename, 7);
title[7] = 0;
if (equalstring(title, (char *) "stdin", false, true)) {
flags = O_RDONLY;
if (filename[5])
return (Socket *) TryNextDevice;
else
filename += 5;
} else if (equalstring(title, (char *) "stdout", false, true)) {
flags = O_WRONLY;
if (filename[6])
return (Socket *) TryNextDevice;
else
filename += 6;
} else if (equalstring(title, (char *) "console", false, true)) {
switch (filename[7]) {
case ':':
++filename;
case 0:
filename += 7;
break;
default:
return (Socket *) TryNextDevice;
}
} else
return (Socket *) TryNextDevice;
if (*filename) {
for (doc = gConsoleList; doc; doc = doc->u.cons.next)
if (doc->kind == kConsoleWindow) {
getwtitle(doc->theWindow, title);
if (equalstring(title, (char *) filename, false, true)) {
if (doc->u.cons.cookie)
sock = (Socket *) doc->u.cons.cookie;
goto found;
}
}
nudoc = true;
doc = NewDocument(false, kConsoleWindow);
setwtitle(doc->theWindow, (char *) filename);
RestoreConsole(doc);
} else {
for (doc = gConsoleList; doc; doc = doc->u.cons.next)
if (doc->kind == kWorksheetWindow) {
if (doc->u.cons.cookie)
sock = (Socket *) doc->u.cons.cookie;
goto found;
}
nudoc = true;
doc = NewDocument(false, kWorksheetWindow);
SetWTitle(doc->theWindow, StringPtr(CurApName));
RestoreConsole(doc);
}
found:
if (!sock) {
errno = 0;
sock = new MPConsoleSocket(doc);
if (sock && errno) {
if (nudoc)
CloseMyWindow(doc->theWindow);
delete sock;
return nil;
}
if (!spinInstalled) {
GUSISetSpin(GUSIConsoleSpin);
spinInstalled = true;
}
} else
((MPConsoleSocket *)sock)->eof = false;
if (!(flags & 1))
doc->u.cons.fence = (*doc->theText)->teLength;
else if (nudoc)
doc->u.cons.fence = 32767;
return sock;
}
/********************* A kinder, gentler, spin **********************/
int GUSIConsoleSpin(spin_msg spin, long)
{
if (!gInBackground && GUSIInterrupt() && gRunningPerl) {
raise(SIGINT);
/* Not reached */
return -1;
}
MainEvent(spin != SP_SELECT && spin != SP_STREAM_READ);
for (DPtr doc = gConsoleList; doc; doc = doc->u.cons.next)
if (doc->dirty) {
if (doc->u.cons.cookie)
HarvestConsole(doc, (MPConsoleSocket *) doc->u.cons.cookie);
doc->dirty = false;
}
return 0;
}